// TerrainLighting.cpp : implementation file
//

#include "StdAfx.h"
#include "TerrainLighting.h"
#include "CryEditDoc.h"
#include ".\Terrain\Heightmap.h"
#include "WaitProgress.h"
#include "GameEngine.h"
#include ".\Terrain\TerrainTexGen.h"
#include "Mission.h"

#define LIGHTING_PREVIEW_RESOLUTION 256
#define SLIDER_SCALE 100.0f

const int MOON_SUN_TRANS_WIDTH = 400;
const int MOON_SUN_TRANS_HEIGHT = 10;
const int MOON_SUN_TRANS_Y = 245;


IMPLEMENT_DYNCREATE(CTerrainLightingFrame,CBaseFrameWnd)

//////////////////////////////////////////////////////////////////////////
class CTerrainLightingViewClass : public IViewPaneClass
{
	//////////////////////////////////////////////////////////////////////////
	// IClassDesc
	//////////////////////////////////////////////////////////////////////////
	virtual ESystemClassID SystemClassID() { return ESYSTEM_CLASS_VIEWPANE; };
	virtual REFGUID ClassID()
	{
		// {8E845DF0-7000-4aae-AEC8-5788DE4C06A3}
		static const GUID guid = { 0x8e845df0, 0x7000, 0x4aae, { 0xae, 0xc8, 0x57, 0x88, 0xde, 0x4c, 0x6, 0xa3 } };
		return guid;
	}
	virtual const char* ClassName() { return _T(LIGHTING_TOOL_WINDOW_NAME); };
	virtual const char* Category() { return "Terrain"; };
	//////////////////////////////////////////////////////////////////////////
	virtual CRuntimeClass* GetRuntimeClass() { return RUNTIME_CLASS(CTerrainLightingFrame); };
	virtual const char* GetPaneTitle() { return _T(LIGHTING_TOOL_WINDOW_NAME); };
	virtual EDockingDirection GetDockingDirection() { return DOCK_FLOAT; };
	virtual CRect GetPaneRect() { return CRect(5,110,755,495); };
	virtual bool SinglePane() { return false; };
	virtual bool WantIdleUpdate() { return true; };
};
REGISTER_CLASS_DESC(CTerrainLightingViewClass)

CTerrainLightingFrame::CTerrainLightingFrame()
{
	CRect rcClient(0,0,1,1);
	Create(WS_CHILD|WS_VISIBLE|WM_VSCROLL,rcClient, AfxGetMainWnd() );
}

BOOL CTerrainLightingFrame::OnInitDialog()
{
	CRect rcClient(0,0,1,1);
	GetClientRect(rcClient);
	dlg.Create(IDD_LIGHTING,this);
	dlg.SetWindowPos(NULL, rcClient.left-5, rcClient.top-5,750,520,SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
	dlg.ShowWindow(1);

	return TRUE;  // return TRUE unless you set the focus to a control
}

CTerrainLighting::CTerrainLighting(CWnd* pParent)
: CDialog(CTerrainLighting::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTerrainLighting)
	m_optLightingAlgo = -1;
	m_sldSunDirection = 240;
	m_sldLongitude = 90;		// equator
//	m_bTerrainShadows = FALSE;
	m_sldILApplySS = 1;
	m_sldSkyQuality=0;
//	m_sldSkyBrightening=0;
	m_sldDawnTime = 355;
	m_sldDawnDuration = 10;
	m_sldDuskTime = 365;
	m_sldDuskDuration = 10;
	m_forceUpdateCheck=gSettings.bForceSkyUpdate;
	//}}AFX_DATA_INIT
	m_pTexGen = new CTerrainTexGen;
	m_pTexGen->Init(LIGHTING_PREVIEW_RESOLUTION,true);
}

CTerrainLighting::~CTerrainLighting()
{
	delete m_pTexGen;
}

void CTerrainLighting::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTerrainLighting)
	DDX_Radio(pDX, IDC_LIGHTING_TYPE_PRECISE, m_optLightingAlgo);
	DDX_Slider(pDX, IDC_SUN_DIRECTION, m_sldSunDirection);
	DDX_Slider(pDX, IDC_SUNMAPLONGITUDE, m_sldLongitude);
	DDX_Check(pDX, IDC_OBJECTTERRAINOCCL, m_sldILApplySS);
	DDX_Slider(pDX, IDC_HEMISAMPLEQ, m_sldSkyQuality);
	DDX_Slider(pDX, IDC_DAWN_SLIDER, m_sldDawnTime);
	DDX_Slider(pDX, IDC_DAWN_DUR_SLIDER, m_sldDawnDuration);
	DDX_Slider(pDX, IDC_DUSK_SLIDER, m_sldDuskTime);
	DDX_Slider(pDX, IDC_DUSK_DUR_SLIDER, m_sldDuskDuration);	
	DDX_Slider(pDX, IDC_LIGHTING_TIME_OF_DAY, m_sldTimeOfADay);
	DDX_Check(pDX, IDC_FORCE_SKY_UPDATE, m_forceUpdateCheck);
	DDX_Control(pDX, IDC_TIME_OF_DAY_EDIT, m_todEdit);
	DDX_Control(pDX, IDC_DAWN_INFO, m_dawnInfoEdit);
	DDX_Control(pDX, IDC_DUSK_INFO, m_duskInfoEdit);
	//	DDX_Check(pDX, IDC_TERRAINSHADOWS, m_bTerrainShadows);
	//	DDX_Slider(pDX, IDC_SKYBRIGHTENING, m_sldSkyBrightening);	
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CTerrainLighting, CDialog)
	//{{AFX_MSG_MAP(CTerrainLighting)
	ON_WM_PAINT()
	ON_WM_HSCROLL()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_BN_CLICKED(IDC_UPDATEIL, OnUpdateIL)
	ON_BN_CLICKED(IDC_OBJECTTERRAINOCCL, OnApplyILSS)
	ON_BN_CLICKED(IDC_APPLY, OnApply)	
	ON_BN_CLICKED(IDC_LIGHTING_IMPORT_BTN, OnFileImport)
	ON_BN_CLICKED(IDC_LIGHTING_EXPORT_BTN, OnFileExport)
	ON_BN_CLICKED(IDC_LIGHTING_TYPE_DYNAMIC_SUN, OnDynamicSun)
	ON_BN_CLICKED(IDC_LIGHTING_TYPE_PRECISE, OnPrecise)
	ON_BN_CLICKED(IDC_FORCE_SKY_UPDATE, OnForceSkyUpdate)
	ON_EN_CHANGE(IDC_DAWN_DUR_INFO, UpdateScrollBarsFromEdits)
	ON_EN_CHANGE(IDC_DUSK_DUR_INFO, UpdateScrollBarsFromEdits)
	ON_EN_CHANGE(IDC_LIGHTING_SUNDIR_EDIT, UpdateScrollBarsFromEdits)
	ON_EN_CHANGE(IDC_LIGHTING_POLE_EDIT, UpdateScrollBarsFromEdits)

	//	ON_BN_CLICKED(IDC_TERRAINSHADOWS, OnTerrainShadows)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTerrainLighting message handlers

void CTerrainLighting::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	RECT rcClient;
	CPen cGrayPen(PS_SOLID, 1, 0x007F7F7F);
	CPen cWhitePen(PS_SOLID, 1, 0x00FFFFFF);
	CPen cRedPen(PS_SOLID, 1, 0x000000FF);

	if (!m_dcMoonSunTrans.m_hDC)
		GenerateMoonSunTransition(false);

	dc.BitBlt(315, MOON_SUN_TRANS_Y, MOON_SUN_TRANS_WIDTH, MOON_SUN_TRANS_HEIGHT, &m_dcMoonSunTrans, 0, 0, SRCCOPY);

	CPen *prevPen = dc.SelectObject(&cRedPen);
	{
		for (int i(0); i<5; ++i)
		{
			int x = 315 + i * (MOON_SUN_TRANS_WIDTH / 4);
			dc.MoveTo(x, MOON_SUN_TRANS_Y - 3);
			dc.LineTo(x, MOON_SUN_TRANS_Y + MOON_SUN_TRANS_HEIGHT + 3);
		}
	}

	CRect rc(19,29,19+LIGHTING_PREVIEW_RESOLUTION,24+LIGHTING_PREVIEW_RESOLUTION);


	// Generate a preview if we don't have one
	if (!m_dcLightmap.m_hDC)
		GenerateLightmap(false);	
	// Draw the preview of the lightmap
	dc.BitBlt(19, 29, LIGHTING_PREVIEW_RESOLUTION, LIGHTING_PREVIEW_RESOLUTION, &m_dcLightmap, 0, 0, SRCCOPY);


	// Draw Sun direction.

	CPoint center = rc.CenterPoint();
//	Vec3 sunVector = GetIEditor()->GetDocument()->GetLighting()->GetSunVector();
/*	sunVector.Normalize();				// should never fail
	sunVector.z = 0;
	sunVector.NormalizeSafe();		// to avoid (0,0,0).Normalize
	CPoint source = center + CPoint(-sunVector.x*120,-sunVector.y*120);
*/
	float fSunRot = 2*gf_PI * (90-m_sldSunDirection)/360.0f;
	float fLongitude = 0.5f*gf_PI-gf_PI * m_sldLongitude/180.0f;

	uint32 dwI=0;
	for(double fAngle=0; fAngle<=2*gf_PI; fAngle+=2*gf_PI/64.0,++dwI)
	{
		const float fR=120;

		Matrix33 a,b,c,m;
		
		a.SetRotationZ(fAngle);
		b.SetRotationX(fLongitude);
		c.SetRotationY(fSunRot);

		m = a*b*c;

		Vec3 vLocalSunDir = Vec3(0,fR,0)*m;
		Vec3 vLocalSunDirLeft = Vec3(-fR*0.05f,fR,fR*0.05f)*m;
		Vec3 vLocalSunDirRight = Vec3(-fR*0.05f,fR,-fR*0.05f)*m;

		CPoint point = center + CPoint((int)vLocalSunDir.x,(int)vLocalSunDir.z);
		CPoint pointLeft = center + CPoint((int)vLocalSunDirLeft.x,(int)vLocalSunDirLeft.z);
		CPoint pointRight = center + CPoint((int)vLocalSunDirRight.x,(int)vLocalSunDirRight.z);

		if(dwI==0)
			dc.MoveTo( point );
		else
		{
			if(vLocalSunDir.y>-0.1f)		// beginning or below surface
			{
				dc.MoveTo( pointLeft );
				dc.LineTo( point );
				dc.LineTo( pointRight );
				dc.MoveTo( point );
			}
		}
	}

//	dc.MoveTo( center );dc.LineTo( source );		// north line


	// Draw a menu bar separator
	GetClientRect(&rcClient);
	dc.SelectObject(&cGrayPen);

	dc.MoveTo(0, 0);
	dc.LineTo(rcClient.right, 0);
	dc.SelectObject(&cWhitePen);
	dc.MoveTo(0, 1);
	dc.LineTo(rcClient.right, 1);

	dc.SelectObject(prevPen);
	
	// Do not call CDialog::OnPaint() for painting messages
}

void CTerrainLighting::GenerateLightmap(bool drawOntoDialog)
{
	BeginWaitCursor();

	// Generate a preview of the light map

	// Create a DC and a bitmap
	if (!m_dcLightmap.m_hDC)
		VERIFY(m_dcLightmap.CreateCompatibleDC(NULL));
	if (!m_bmpLightmap.m_hObject)
		VERIFY(m_bmpLightmap.CreateBitmap(LIGHTING_PREVIEW_RESOLUTION, LIGHTING_PREVIEW_RESOLUTION, 1, 32, NULL));
	m_dcLightmap.SelectObject(&m_bmpLightmap);

	// Calculate the lighting.
	m_pTexGen->InvalidateLighting();

	int flags=ETTG_LIGHTING|ETTG_QUIET|ETTG_ABGR|ETTG_INVALIDATE_LAYERS|ETTG_BAKELIGHTING;

	// no texture needed
	flags|=ETTG_NOTEXTURE;
	flags|=ETTG_SHOW_WATER;

	m_pTexGen->GenerateSurfaceTexture(flags,m_lightmap);

	 //put m_lightmap into m_bmpLightmap
	{
		BITMAPINFO bi;

		ZeroStruct(bi);
		bi.bmiHeader.biSize = sizeof(bi);
		bi.bmiHeader.biWidth = m_lightmap.GetWidth();
		bi.bmiHeader.biHeight = -m_lightmap.GetHeight();
		bi.bmiHeader.biBitCount = 32;
		bi.bmiHeader.biPlanes = 1;
		bi.bmiHeader.biCompression = BI_RGB;

		SetDIBits(m_dcLightmap.m_hDC,(HBITMAP)m_bmpLightmap.GetSafeHandle(),0,m_lightmap.GetHeight(),m_lightmap.GetData(),&bi,false);
	}

	// Update the preview
	if (drawOntoDialog)
	{
		RECT rcUpdate;
		::SetRect(&rcUpdate, 10, 10, 20 + LIGHTING_PREVIEW_RESOLUTION, 30 + LIGHTING_PREVIEW_RESOLUTION);
		InvalidateRect(&rcUpdate, FALSE);
		UpdateWindow();
	}

	GetIEditor()->GetGameEngine()->ReloadEnvironment();
	GetIEditor()->UpdateViews(eRedrawViewports);
	EndWaitCursor();
}

void CTerrainLighting::GenerateMoonSunTransition(bool drawOntoDialog)
{
	BeginWaitCursor();

	// Generate a preview of the moon sun transitions

	// Create a DC and a bitmap
	if (!m_dcMoonSunTrans.m_hDC)
		VERIFY(m_dcMoonSunTrans.CreateCompatibleDC(NULL));
	if (!m_bmpMoonSunTrans.m_hObject)
		VERIFY(m_bmpMoonSunTrans.CreateBitmap(MOON_SUN_TRANS_WIDTH, MOON_SUN_TRANS_HEIGHT, 1, 32, NULL));
	m_dcMoonSunTrans.SelectObject(&m_bmpMoonSunTrans);

	unsigned int *pData(&m_moonSunTrans.GetData()[0]);
	for (int x(0); x<MOON_SUN_TRANS_WIDTH; ++x)
	{
		pData[x] = 0;
		pData[x + MOON_SUN_TRANS_WIDTH * (MOON_SUN_TRANS_HEIGHT - 1)] = 0;
	}

	// render sun/moon transition as overlay into DIB
	for (int x(0); x<MOON_SUN_TRANS_WIDTH; ++x)
	{
		// render gradient
		{
			ColorF sun(1, 0.9f, 0.4f, 1);
			ColorF moon(0.4f, 0.4f, 1, 1);
			ColorF black(0, 0, 0, 1);

			ColorF col;

			float f(2.0f * x / (float) MOON_SUN_TRANS_WIDTH);
			if (f >= 1.0f)
			{
				f -= 1.0f;

				float t((float) m_sldDuskTime / (float) (12 * 60));
				float d((float) m_sldDuskDuration / (float) (12 * 60));

				float m(t + d * 0.5f);
				float s(t - d * 0.5f);

				if (f < s)
					col = sun;
				else if (f >= m)
					col = moon;
				else
				{
					assert(s < m);
					float b(0.5f * (s + m));
					if (f < b)
						col.lerpFloat(sun, black, (f-s) / (b-s));
					else
						col.lerpFloat(black, moon, (f-b) / (m-b));
				}
			}
			else
			{
				float t((float) m_sldDawnTime / (float) (12 * 60));
				float d((float) m_sldDawnDuration / (float) (12 * 60));

				float s(t + d * 0.5f);
				float m(t - d * 0.5f);

				if (f < m)
					col = moon;
				else if (f >= s)
					col = sun;
				else
				{
					assert(s > m);
					float b(0.5f * (s + m));
					if (f < b)
						col.lerpFloat(moon, black, (f-m) / (b-m));
					else
						col.lerpFloat(black, sun, (f-b) / (s-b));
				}
			}

			ColorB _col(col);
			unsigned int finalCol((_col.r << 16) | (_col.g << 8) | _col.b);

			unsigned int *pData(&m_moonSunTrans.GetData()[x + MOON_SUN_TRANS_WIDTH]);
			for (int y(1); y<MOON_SUN_TRANS_HEIGHT-1; ++y)
			{
				*pData = finalCol;
				pData += MOON_SUN_TRANS_WIDTH;
			}
		}
	}

	// put m_moonSunTrans into m_bmpMoonSunTrans
	{
		BITMAPINFO bi;

		ZeroStruct(bi);
		bi.bmiHeader.biSize = sizeof(bi);
		bi.bmiHeader.biWidth = m_moonSunTrans.GetWidth();
		bi.bmiHeader.biHeight = -m_moonSunTrans.GetHeight();
		bi.bmiHeader.biBitCount = 32;
		bi.bmiHeader.biPlanes = 1;
		bi.bmiHeader.biCompression = BI_RGB;

		SetDIBits(m_dcMoonSunTrans.m_hDC, (HBITMAP) m_bmpMoonSunTrans.GetSafeHandle(), 0, m_moonSunTrans.GetHeight(), m_moonSunTrans.GetData(), &bi, false);
	}

	// Update the preview
	if (drawOntoDialog)
	{
		RECT rcUpdate;
		::SetRect(&rcUpdate, 315, MOON_SUN_TRANS_Y-3, 315 + MOON_SUN_TRANS_WIDTH, MOON_SUN_TRANS_Y+3 + MOON_SUN_TRANS_HEIGHT);
		InvalidateRect(&rcUpdate, FALSE);
		UpdateWindow();
	}

	GetIEditor()->GetGameEngine()->ReloadEnvironment();
	GetIEditor()->UpdateViews(eRedrawViewports);
	EndWaitCursor();
}

BOOL CTerrainLighting::OnInitDialog() 
{
	CDialog::OnInitDialog();

	////////////////////////////////////////////////////////////////////////
	// Initialize the dialog with the settings from the document
	////////////////////////////////////////////////////////////////////////
	m_originalLightSettings = *GetIEditor()->GetDocument()->GetLighting();

	CSliderCtrl ctrlSlider;

	CLogFile::WriteLine("Loading lighting dialog...");

	// Set the ranges for the slider controls
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_SUN_DIRECTION)->m_hWnd));
	ctrlSlider.SetRange(0, 360, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_SUNMAPLONGITUDE)->m_hWnd));
	ctrlSlider.SetRange(0, 180, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_HEMISAMPLEQ)->m_hWnd));
	ctrlSlider.SetRange(0, 10, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_DAWN_SLIDER)->m_hWnd));
	ctrlSlider.SetRange(0, 12 * 60, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_DAWN_DUR_SLIDER)->m_hWnd));
	ctrlSlider.SetRange(0, 60, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_DUSK_SLIDER)->m_hWnd));
	ctrlSlider.SetRange(0, 12 * 60, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_DUSK_DUR_SLIDER)->m_hWnd));
	ctrlSlider.SetRange(0, 60, TRUE);
	ctrlSlider.Detach();
	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_LIGHTING_TIME_OF_DAY)->m_hWnd));
	ctrlSlider.SetRange(0, 24*SLIDER_SCALE, TRUE);
	ctrlSlider.Detach();
	//	VERIFY(ctrlSlider.Attach(GetDlgItem(IDC_SKYBRIGHTENING)->m_hWnd));
	//	ctrlSlider.SetRange(0, 100, TRUE);
	//	ctrlSlider.Detach();


	m_lightmap.Allocate( LIGHTING_PREVIEW_RESOLUTION,LIGHTING_PREVIEW_RESOLUTION );
	m_moonSunTrans.Allocate(MOON_SUN_TRANS_WIDTH, MOON_SUN_TRANS_HEIGHT);

	m_dawnDurationEdit.Create(this,IDC_DAWN_DUR_INFO,CNumberCtrl::LEFTALIGN );
	m_dawnDurationEdit.SetRange(0,60);
	m_dawnDurationEdit.SetStep(1);

	m_duskDurationEdit.Create( this,IDC_DUSK_DUR_INFO,CNumberCtrl::LEFTALIGN );
	m_duskDurationEdit.SetRange(0,60);
	m_duskDurationEdit.SetStep(1);

	m_sunDirEdit.Create( this,IDC_LIGHTING_SUNDIR_EDIT,CNumberCtrl::LEFTALIGN );
	m_sunDirEdit.SetRange(0,360);
	m_sunDirEdit.SetStep(1);

	m_poleEdit.Create( this,IDC_LIGHTING_POLE_EDIT,CNumberCtrl::LEFTALIGN );
	m_poleEdit.SetRange(0,180);
	m_poleEdit.SetStep(1);

	// Synchronize the controls with the values from the document
	UpdateControls();

	return TRUE; // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CTerrainLighting::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	////////////////////////////////////////////////////////////////////////
	// Update the document with the values from the sliders
	////////////////////////////////////////////////////////////////////////

	UpdateData(TRUE);

	LightingSettings *ls = GetIEditor()->GetDocument()->GetLighting();

	const uint32 scrollID = pScrollBar->GetDlgCtrlID();

	ls->iSunRotation = m_sldSunDirection;
	ls->iILApplySS = m_sldILApplySS;
	ls->iHemiSamplQuality = m_sldSkyQuality;
	ls->iLongitude = m_sldLongitude;
	//	ls->iSkyBrightening = m_sldSkyBrightening;

	ls->iDawnTime = m_sldDawnTime;
	ls->iDawnDuration = m_sldDawnDuration;
	ls->iDuskTime = m_sldDuskTime;
	ls->iDuskDuration = m_sldDuskDuration;
	
	float fHour = m_sldTimeOfADay/SLIDER_SCALE;
	int nHour = floor(fHour);
	int nMins = (fHour - floor(fHour)) * 60.0f;
	m_todEdit.SetTime(nHour,nMins);

	SetTime(m_sldTimeOfADay/SLIDER_SCALE,m_forceUpdateCheck);

	// We modified the document
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);

	// Update the preview
	switch(scrollID)
	{
	case IDC_DAWN_SLIDER:
	case IDC_DAWN_DUR_SLIDER:
	case IDC_DUSK_SLIDER:
	case IDC_DUSK_DUR_SLIDER:
	case IDC_LIGHTING_TIME_OF_DAY:
		{
			if (m_forceUpdateCheck)
				GenerateMoonSunTransition();
			break;
		}
	default:
		{
			GenerateLightmap();
			break;
		}
	}

	UpdateMoonSunTransitionLabels();

	//case IDC_SUNMAPLONGITUDE:
	//case IDC_SUN_DIRECTION:
	//	{
	//		UpdateMoonSunTransitionLabels();
	//		break;
	//	}

	CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}



void CTerrainLighting::OnUpdateIL() 
{
	////////////////////////////////////////////////////////////////////////
	// Synchronize value in the document
	////////////////////////////////////////////////////////////////////////

	UpdateData(TRUE);

	// We modified the document
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);

	CScrollBar *pScrollBar = (CScrollBar*)GetDlgItem(IDC_HEMISAMPLEQ);
	pScrollBar->EnableWindow(true);
}

void CTerrainLighting::OnApplyILSS()
{
	////////////////////////////////////////////////////////////////////////
	// Synchronize value in the document
	////////////////////////////////////////////////////////////////////////

	UpdateData(TRUE);

	GetIEditor()->GetDocument()->GetLighting()->iILApplySS = m_sldILApplySS;

	// We modified the document
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);
}

void CTerrainLighting::OnFileImport() 
{
	////////////////////////////////////////////////////////////////////////
	// Import the lighting settings
	////////////////////////////////////////////////////////////////////////

	char szFilters[] = "Light Settings (*.lgt)|*.lgt||";
	CString fileName;

	if (CFileUtil::SelectFile( szFilters,GetIEditor()->GetLevelFolder(),fileName ))
	{
		CLogFile::WriteLine("Importing light settings...");

		XmlNodeRef node = XmlHelpers::LoadXmlFromFile( fileName );
		GetIEditor()->GetDocument()->GetLighting()->Serialize( node,true );

		// We modified the document
		GetIEditor()->SetModifiedFlag();
		GetIEditor()->SetModifiedModule(eModifiedTerrain);

		// Update the controls with the settings from the document
		UpdateControls();

		// Update the preview
		GenerateLightmap();
		GenerateMoonSunTransition();
	}
}

void CTerrainLighting::OnFileExport() 
{
	////////////////////////////////////////////////////////////////////////
	// Export the lighting settings
	////////////////////////////////////////////////////////////////////////
	
	char szFilters[] = "Light Settings (*.lgt)|*.lgt||";
	CString fileName;
	if (CFileUtil::SelectSaveFile( szFilters,"lgt",GetIEditor()->GetLevelFolder(),fileName ))
	{
		CLogFile::WriteLine("Exporting light settings...");

		// Write the light settings into the archive
		XmlNodeRef node = XmlHelpers::CreateXmlNode( "LightSettings" );
		GetIEditor()->GetDocument()->GetLighting()->Serialize( node,false );
		XmlHelpers::SaveXmlNode( node,fileName );
	}
}

void CTerrainLighting::UpdateControls()
{
	////////////////////////////////////////////////////////////////////////	
	// Update the controls with the settings from the document
	////////////////////////////////////////////////////////////////////////

	LightingSettings *ls = GetIEditor()->GetDocument()->GetLighting();
//	m_bTerrainShadows = ls->bTerrainShadows;
	m_sldSunDirection = ls->iSunRotation;
	m_sldILApplySS = ls->iILApplySS;
	m_sldSkyQuality = ls->iHemiSamplQuality;
//	m_sldSkyBrightening = ls->iSkyBrightening;
	m_sldLongitude = ls->iLongitude;

	m_sldDawnTime = clamp_tpl(ls->iDawnTime, 0, 12 * 60);
	m_sldDawnDuration = clamp_tpl(ls->iDawnDuration, 0, 60);
	m_sldDuskTime = clamp_tpl(ls->iDuskTime, 0, 12 * 60);
	m_sldDuskDuration = clamp_tpl(ls->iDuskDuration, 0, 60);	

	// TOD slider
	float fHour = GetTime();
	int nHour = floor(fHour);
	int nMins = (fHour - floor(fHour)) * 60.0f;
	m_todEdit.SetTime(nHour,nMins);

	m_sldTimeOfADay = (int)clamp_tpl(fHour*SLIDER_SCALE,0.0f,24*SLIDER_SCALE);


	switch (ls->eAlgo)
	{
		case ePrecise:
			m_optLightingAlgo = 0;
			break;

		case eDynamicSun:
			m_optLightingAlgo = 1;
			break;

		default: assert(0);
	}
	
	UpdateData(FALSE);

	UpdateMoonSunTransitionLabels();
}

void CTerrainLighting::OnDynamicSun() 
{
	GetIEditor()->GetDocument()->GetLighting()->eAlgo = eDynamicSun;
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);
	UpdateControls();
}

void CTerrainLighting::OnPrecise()
{
	GetIEditor()->GetDocument()->GetLighting()->eAlgo = ePrecise;
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);
	UpdateControls();
}

BOOL CTerrainLighting::DestroyWindow() 
{
	return CDialog::DestroyWindow();
}

//////////////////////////////////////////////////////////////////////////
void CTerrainLighting::OnMouseMove(UINT nFlags, CPoint point)
{
	CDialog::OnMouseMove(nFlags, point);
}

//////////////////////////////////////////////////////////////////////////
void CTerrainLighting::OnLButtonDown(UINT nFlags, CPoint point)
{
	CDialog::OnLButtonDown(nFlags, point);
}

//////////////////////////////////////////////////////////////////////////
void CTerrainLighting::OnLButtonUp(UINT nFlags, CPoint point)
{
	CDialog::OnLButtonUp(nFlags, point);
}

void CTerrainLighting::OnOK(void)
{
	UpdateScrollBarsFromEdits();

	CWaitCursor wait;
	// When exiting lighting dialog.
	GetIEditor()->GetGameEngine()->ReloadEnvironment();
}

void CTerrainLighting::OnApply(void)
{
	CWaitCursor wait;
	// When exiting lighting dialog.
	GetIEditor()->GetGameEngine()->ReloadEnvironment();
	GetIEditor()->Notify( eNotify_OnUpdateViewports ) ;
	m_originalLightSettings = *GetIEditor()->GetDocument()->GetLighting();
}

void CTerrainLighting::OnCancel(void)
{
	LightingSettings *ls = GetIEditor()->GetDocument()->GetLighting();
	*ls = m_originalLightSettings;

	GetIEditor()->GetGameEngine()->ReloadEnvironment();
	GetIEditor()->UpdateViews(eRedrawViewports);
	CDialog::OnCancel();
}

void CTerrainLighting::UpdateMoonSunTransitionLabels()
{
	char text[32]; text[sizeof(text)-1] = '\0';	
	{
		_snprintf(text, sizeof(text) - 1,"%.2d:%.2d", m_sldDawnTime / 60, m_sldDawnTime % 60);
		GetDlgItem(IDC_DAWN_INFO)->SetWindowText(text);
	}
	{
		_snprintf(text, sizeof(text) - 1,"%.2d:%.2d", 12 + (m_sldDuskTime / 60), m_sldDuskTime % 60);
		GetDlgItem(IDC_DUSK_INFO)->SetWindowText(text);
	}

	m_dawnDurationEdit.SetValue(m_sldDawnDuration);
	m_duskDurationEdit.SetValue(m_sldDuskDuration);
	m_poleEdit.SetValue(m_sldLongitude);
	m_sunDirEdit.SetValue(m_sldSunDirection);
}

float CTerrainLighting::GetTime() const
{
	float fTime = 0;
	if (GetIEditor()->GetDocument()->GetCurrentMission())
		fTime = GetIEditor()->GetDocument()->GetCurrentMission()->GetTime();
	return fTime;
}

//////////////////////////////////////////////////////////////////////////
void CTerrainLighting::SetTime( const float fHour,const bool bforceSkyUpate)
{
	ITimeOfDay *pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
	pTimeOfDay->SetTime( fHour, bforceSkyUpate );

	if (GetIEditor()->GetDocument()->GetCurrentMission())
		GetIEditor()->GetDocument()->GetCurrentMission()->SetTime(fHour);

		GetIEditor()->Notify( eNotify_OnTimeOfDayChange );
}

void CTerrainLighting::UpdateScrollBarsFromEdits()
{
	CString str("");
	int h,m;
	h=0;
	m=0;

	m_todEdit.GetWindowText(str);
	sscanf( str,_T("%02d:%02d"),&h,&m );
	float fTime = (float)h + (float)m/60.0f;
	SetTime( fTime,m_forceUpdateCheck );

	m_dawnInfoEdit.GetWindowText(str);
	sscanf( str,_T("%02d:%02d"),&h,&m );
	if (h>=12)
		m_sldDawnTime = (h-12)*60 + m;
	else
		m_sldDawnTime = h*60 + m;

	m_duskInfoEdit.GetWindowText(str);
	sscanf( str,_T("%02d:%02d"),&h,&m );
	if (h>=12)
		m_sldDuskTime = (h-12)*60 + m;
	else
		m_sldDuskTime = h*60 + m;

	m_sldDawnDuration=m_dawnDurationEdit.GetValue();
	m_sldDuskDuration=m_duskDurationEdit.GetValue();
	m_sldSunDirection = m_sunDirEdit.GetValue();
	m_sldLongitude = m_poleEdit.GetValue();

	LightingSettings *ls = GetIEditor()->GetDocument()->GetLighting();
	ls->iDawnTime = m_sldDawnTime;
	ls->iDuskTime = m_sldDuskTime;
	ls->iDawnDuration = m_sldDawnDuration;
	ls->iDuskDuration = m_sldDuskDuration;
	ls->iLongitude = m_sldLongitude;
	ls->iSunRotation = m_sldSunDirection;

	UpdateControls();
	UpdateDocument();
}

void CTerrainLighting::UpdateDocument()
{
	// Update the preview
	if (m_forceUpdateCheck)
		GenerateLightmap();
	else
		GenerateMoonSunTransition();

	UpdateMoonSunTransitionLabels();

	// We modified the document
	GetIEditor()->SetModifiedFlag();
	GetIEditor()->SetModifiedModule(eModifiedTerrain);
}

void CTerrainLighting::OnForceSkyUpdate()
{
	m_forceUpdateCheck=!m_forceUpdateCheck;
	ITimeOfDay *pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
	pTimeOfDay->SetTime( GetTime(), m_forceUpdateCheck);
	gSettings.bForceSkyUpdate=m_forceUpdateCheck;
}
